﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using System.Xml.Serialization;

namespace MapEditor
{
    public class Module : IXmlSerializable
    {
        public String name;

        //taille de la map
        private int sizeX;
        private int sizeY;

        //
        public bool north;
        public bool south;
        public bool east;
        public bool west;

        public bool start;
        public bool end;

        // les 4 layers
        public TileLayer background
        {
            private set;
            get;
        }
        public TileLayer staticLayer
        {
            private set;
            get;
        }
        public TileLayer foreground
        {
            private set;
            get;
        }
        public TileLayer dynamicLayer
        {
            private set;
            get;
        }

        private TileLayer[] layerTab;

        public Module()
        {
            this.name = null;
            this.sizeX = -1;
            this.sizeY = -1;
            layerTab = new TileLayer[4];
        }

        public Module(String name, int sizeX, int sizeY)
        {
            this.name = name;
            this.sizeX = sizeX;
            this.sizeY = sizeY;
            layerTab = new TileLayer[4];

            if (name != "")
            {
                layerTab[0] = foreground = new TileLayer(getInitialisedTab(-1));
                layerTab[1] = staticLayer = new TileLayer(getInitialisedTab(-1));
                layerTab[2] = background = new TileLayer(getInitialisedTab(0));
                layerTab[3] = dynamicLayer = new TileLayer(getInitialisedTab(0));
            }
            else
            {
                layerTab[0] = foreground = new TileLayer(getInitialisedTab(-1));
                layerTab[1] = staticLayer = new TileLayer(getInitialisedTab(-1));
                layerTab[2] = background = new TileLayer(getInitialisedTab(-1));
                layerTab[3] = dynamicLayer = new TileLayer(getInitialisedTab(0));
            }
        }

        /// <summary>
        /// retourne un tableau initialisé pour construire un layer.
        /// </summary>
        /// <param name="value"> valeur par defaut du tableau</param>
        private int[,] getInitialisedTab(int value)
        {
            int[,] tmp = new int[sizeY, sizeX];
            for (int i = 0; i < sizeY; i++)
                for (int j = 0; j < sizeX; j++)
                    tmp[i, j] = value;
            return tmp;
        }

        /// <summary>
        /// modifie une tile d'un layer.
        /// </summary>
        /// <param name="layer"> layer à modifier</param>
        /// <param name="x"> coordonné x de la tile à modifier</param>
        /// <param name="y"> coordonné y de la tile à modifier</param>
        /// <param name="listview"> listview correspondant à l'onglet séléctionné</param>
        public void changeTile(int layerNumber, int x, int y, int newId)
        {
            if (layerTab[layerNumber][x, y] != -2 /*hors map*/ && layerTab[layerNumber][x, y] != newId)
            {
                Tile t =  new Tile(foreground[x, y], staticLayer[x, y], background[x, y], dynamicLayer[x, y]);
                t[layerNumber] = newId;
                layerTab[layerNumber][x, y] = newId;
            }
        }

        /// <summary>
        /// modifie une tile d'un layer.
        /// </summary>
        /// <param name="x"> coordonné x de la tile à modifier</param>
        /// <param name="y"> coordonné y de la tile à modifier</param>
        /// <param name="listview"> nouvelle Tile</param>
        public void changeTile(int x, int y, Tile newtile)
        {
            if (background[x, y] != -2) //*hors map
            {
                foreground[x, y] = newtile.fg;
                background[x, y] = newtile.bg;
                staticLayer[x, y] = newtile.o;
                dynamicLayer[x, y] = newtile.c;
            }
        }

        /// <summary>
        /// modifie une tile d'un layer. sans ajouter à l'undo stack. utilisé uniquement par la classe Undo
        /// </summary>
        /// <param name="x"> coordonné x de la tile à modifier</param>
        /// <param name="y"> coordonné y de la tile à modifier</param>
        /// <param name="listview"> nouvelle Tile</param>
        public void changeTileNoUndo(int x, int y, Tile newtile)
        {
            if (background[x, y] != -2) // hors map
            {
                foreground[x, y] = newtile.fg;
                background[x, y] = newtile.bg;
                staticLayer[x, y] = newtile.o;
                dynamicLayer[x, y] = newtile.c;
            }
        }

        public Tile getTile(Vector2I v)
        {
            return (new Tile(foreground[v.x, v.y], staticLayer[v.x, v.y], background[v.x, v.y], dynamicLayer[v.x, v.y]));
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            name = reader.GetAttribute("name");
            int deth = reader.Depth;
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.Name == "link")
                        while (!(reader.LocalName == "link" && reader.NodeType == XmlNodeType.EndElement))
                        {
                            if (reader.Read() && reader.NodeType == XmlNodeType.Element)
                            {
                                if (reader.Name == "north")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            north = (reader.Value == "True");
                                    }
                                }
                                else if (reader.Name == "south")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            south = (reader.Value == "True");
                                    }
                                }
                                else if (reader.Name == "east")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            east = (reader.Value == "True");
                                    }
                                }
                                else if (reader.Name == "west")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            west = (reader.Value == "True");
                                    }
                                }
                                else if (reader.Name == "start")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            start = (reader.Value == "True");
                                    }
                                }
                                else if (reader.Name == "end")
                                {
                                    if (reader.Read())
                                    {
                                        if (reader.NodeType == XmlNodeType.Text)
                                            end = (reader.Value == "True");
                                    }
                                }
                            }
                            if (reader.EOF == true)
                                break;
                    }
                    else if (reader.Name == "background")
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            background = new TileLayer();
                            background.ReadXml(reader);
                        }
                    }
                    else if (reader.Name == "staticLayer")
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            staticLayer = new TileLayer();
                            staticLayer.ReadXml(reader);
                        }
                    }
                    else if (reader.Name == "foreground")
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            foreground = new TileLayer();
                            foreground.ReadXml(reader);
                        }
                    }
                    else if (reader.Name == "dynamicLayer")
                    {
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            dynamicLayer = new TileLayer();
                            dynamicLayer.ReadXml(reader);
                        }
                    }
                }
                if (deth == reader.Depth)
                {
                    reader.Read();
                    break;
                }
            }
            layerTab[0] = foreground;
            layerTab[1] = staticLayer;
            layerTab[2] = background;
            layerTab[3] = dynamicLayer;
            if (foreground == null)
                throw new Exception("module " + name + ": layer foreground manquant");
            if (staticLayer == null)
                throw new Exception("module " + name + ": layer staticLayer manquant");
            if (background == null)
                throw new Exception("module " + name + ": layer background manquant");
            if (dynamicLayer == null)
                throw new Exception("module " + name + ": layer dynamicLayer manquant");
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("name", name);
            writer.WriteStartElement("link");
            writer.WriteElementString("north", north.ToString());
            writer.WriteElementString("south", south.ToString());
            writer.WriteElementString("east", east.ToString());
            writer.WriteElementString("west", west.ToString());
            writer.WriteElementString("start", start.ToString());
            writer.WriteElementString("end", end.ToString());
            writer.WriteEndElement();

            XmlAttributeOverrides overrides = new XmlAttributeOverrides();
            XmlAttributes attr = new XmlAttributes();
            attr.XmlRoot = new XmlRootAttribute("background");
            overrides.Add(typeof(TileLayer), attr);
            XmlSerializer xs = new XmlSerializer(typeof(TileLayer), overrides);
            xs.Serialize(writer, background);

            overrides = new XmlAttributeOverrides();
            attr = new XmlAttributes();
            attr.XmlRoot = new XmlRootAttribute("staticLayer");
            overrides.Add(typeof(TileLayer), attr);
            xs = new XmlSerializer(typeof(TileLayer), overrides);
            xs.Serialize(writer, staticLayer);

            overrides = new XmlAttributeOverrides();
            attr = new XmlAttributes();
            attr.XmlRoot = new XmlRootAttribute("foreground");
            overrides.Add(typeof(TileLayer), attr);
            xs = new XmlSerializer(typeof(TileLayer), overrides);
            xs.Serialize(writer, foreground);

            overrides = new XmlAttributeOverrides();
            attr = new XmlAttributes();
            attr.XmlRoot = new XmlRootAttribute("dynamicLayer");
            overrides.Add(typeof(TileLayer), attr);
            xs = new XmlSerializer(typeof(TileLayer), overrides);
            xs.Serialize(writer, dynamicLayer);
        }

        internal void setSize(int sizeX, int sizeY)
        {
            this.sizeX = sizeX;
            this.sizeY = sizeY;
            // TODO : realoc des  layer
        }
    }
}
